package com.atguigu.tingshu.search.service.impl;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.CategoryFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.BaseCategoryView;

import com.atguigu.tingshu.search.service.ItemService;
import com.atguigu.tingshu.vo.search.AlbumInfoDetailVo;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class ItemServiceImpl implements ItemService {

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient ;

    @Autowired
    private CategoryFeignClient categoryFeignClient ;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient ;

    /**
     * @Autowired在进行bean的注入的时候，默认情况下是先按照类型进行注入。如果在spring容器中存在同一个类型多个实例
     * 那么此时就会按照属性名称注入。 如果使用属性名称从spring容器中找不到对应的bean，那么注入失败了。
     */
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor ;

    @Autowired
    private RedissonClient redissonClient ;

    /**
     * 异步化改造的再次优化点：针对一个业务操作最好使用一个独立的线程池
     */

    @Override
    public AlbumInfoDetailVo item(Long albumId) {

        // 判断专辑的id在布隆过滤器中是否存在
        RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        if(!bloomFilter.contains(albumId)) {
            log.info("albumId为： {} 在布隆过滤器中不存在的..." , albumId);
            return new AlbumInfoDetailVo() ;
        }

        // 创建一个AlbumInfoDetailVo对象，封装详情数据
        AlbumInfoDetailVo albumInfoDetailVo = new AlbumInfoDetailVo() ;

        // 根据专辑的id查询专辑的基本数据
        CompletableFuture<AlbumInfo> cf1 = CompletableFuture.supplyAsync(() -> {
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(albumId);
            AlbumInfo albumInfo = albumInfoResult.getData();
            albumInfoDetailVo.setAlbumInfo(albumInfo);
            log.info("根据专辑的id查询专辑的基本数据....albumId: {}" , albumId);
            return albumInfo;
        } , threadPoolExecutor);

        // 根据专辑的id查找专辑的统计数据
        CompletableFuture<Void> cf2 = CompletableFuture.runAsync(() -> {
            Result<AlbumStatVo> albumStatVoResult = albumInfoFeignClient.findAlbumStatByAlbumId(albumId);
            AlbumStatVo albumStatVo = albumStatVoResult.getData();
            albumInfoDetailVo.setAlbumStatVo(albumStatVo);
            log.info("根据专辑的id查找专辑的统计数据....albumId: {}", albumId);
        }, threadPoolExecutor);

        // 根据专辑的三级分类的id查询分类数据
        CompletableFuture<Void> cf3 = cf1.thenAcceptAsync(albumInfo -> {
            Result<BaseCategoryView> categoryViewResult = categoryFeignClient.findCategoryByC3Id(albumInfo.getCategory3Id());
            BaseCategoryView baseCategoryView = categoryViewResult.getData();
            albumInfoDetailVo.setBaseCategoryView(baseCategoryView);
            log.info("根据专辑的三级分类的id查询分类数据....albumId: {}", albumId);
        }, threadPoolExecutor);


        // 根据专辑的作者的id查询专辑的作者数据
        CompletableFuture<Void> cf4 = cf1.thenAcceptAsync(albumInfo -> {
            Result<UserInfo> userInfoResult = userInfoFeignClient.getUserInfoById(albumInfo.getUserId());
            UserInfo userInfo = userInfoResult.getData();
            albumInfoDetailVo.setAnnouncer(userInfo);
            log.info("根据专辑的三级分类的id查询分类数据....albumId: {}", albumId);
        }, threadPoolExecutor);

        // 多任务的组合，让当前线程阻塞
        CompletableFuture.allOf(cf1 , cf2 , cf3 , cf4).join() ;

        // 返回AlbumInfoDetailVo对象
        return albumInfoDetailVo;
    }
}
